目標很簡單:先量再快。
這篇帶你一步一步用 Nsight Systems(看「整體流程/時間線」)和 Nsight Compute(看「單支 kernel 的瓶頸」),再搭配 程式內部量測、幾個經典優化手法與排錯清單。看完就能從「勉強能跑」,變成「知道為什麼慢、怎麼讓它快」。
你想知道:我的時間花在哪?拷貝多還是算多?kernel 能不能重疊?
nsys。也有 GUI(Nsight Systems),安裝後可直接開啟 .nsys-rep 報告。nsys profile -t cuda,nvtx --stats=true -o report ./your_app
# 會產生 report.nsys-rep(GUI用)和摘要
cudaMemcpy、各個 kernel 的開始/結束與是否重疊。cudaDeviceSynchronize(),改用 events 或 stream 回調,只在必要點同步。範例圖:
你想知道:這支 kernel 到底卡在「記憶體」還是「算力」?warp 有沒有分歧?occupancy 夠不夠?
# 跑所有常用分析段落(第一次用這招最省事)
ncu --set full ./your_app
# 只針對名稱含 foo 的 kernel
ncu --set full --kernels ".*foo.*" ./your_app
也可用 GUI(Nsight Compute)直接打開 .ncu-rep,圖表更容易理解。
Summary:牆鐘時間、呼叫次數、平均耗時。
Launch Statistics / Occupancy:
Memory Workload Analysis:
Scheduler / Warp State:
Speed of Light / Roofline(GUI):
cudaEvent_t a,b; cudaEventCreate(&a); cudaEventCreate(&b);
cudaEventRecord(a);
myKernel<<<grid,block,shared,stream>>>(...);
cudaEventRecord(b); cudaEventSynchronize(b);
float ms=0; cudaEventElapsedTime(&ms,a,b);
printf("kernel took %.3f ms\n", ms);
優點:準確抓 GPU 執行時間。缺點:看不到細節,搭配 Nsight 才完整。
#include <nvToolsExt.h>
nvtxRangePushA("Stage: HtoD Copy");
// ... do copy ...
nvtxRangePop();
Coalesced access(相鄰 thread 讀相鄰位址):重排資料或索引,避免跳躍。
Shared Memory 做 tiling:重複使用的資料先搬到共享記憶體,少碰 DRAM。
tile[T][T+1])。Read-only broadcast 用 constant/texture cache:所有 thread 都讀同一數值時,constant memory 很省。
避免無效搬運:把多次小 cudaMemcpy 合併成一次大拷貝;Host buffer 用 pinned memory。
Unified Memory 若造成大量 page fault:
cudaMemPrefetchAsync() 預取到裝置;或改回顯式 cudaMemcpy。if 分兩路,就會排隊跑 → 用資料分群、分支轉算術(有時可用 ?: 或 max/min)、或把差異大的資料拆到不同 kernel。用 cudaOccupancyMaxPotentialBlockSize() 或 Nsight 建議值找 block size sweet spot。
暫存器爆量會限縮 occupancy:
-Xptxas -v 與 Nsight 的 Register Usage;__restrict__ 幫編譯器別名分析。Shared memory 用太多也會卡 occupancy:檢討 tile 大小。
float 甚至 FP16/TF32(用對硬體和庫)可大幅提升吞吐。-use_fast_math 或 __frcp_rn、__fsqrt_rn 等(需衡量精度)。numactl)。| 症狀 | 常見原因 | 立即檢查 | 快速解法 |
|---|---|---|---|
| 拷貝時間占比超高 | 太多小 cudaMemcpy、Unified Memory 頻繁遷移 |
Nsight Systems 的 API Summary | 合併拷貝、pinned host、streams 重疊、cudaMemPrefetchAsync |
| Kernel 很慢、DRAM 吞吐高 | 記憶體受限 | NCU 的 Memory Workload / Roofline | Coalesced、tiling 到 shared、提高重用率、壓縮資料 |
| Kernel 很慢、算力利用高 | 算力受限 | NCU Roofline/SM Active | fast-math、混合精度、庫函式、演算法改寫 |
| Warp stalls: barrier/sync 多 | 過度同步、atomic 爆量 | NCU Warp Stall Reasons | 降低同步頻率、先 local 彙整再全域原子、分塊 |
| Occupancy 低 | 暫存器/SMEM 過量、block size 不佳 | NCU Launch Stats / ptxas -v | 調整 block size、減少暫存器/SMEM、分割 kernel |
| 結果對但時快時慢 | 系統雜訊/時脈/溫度、動態時鐘 | 多次量測 | 取多次平均、暖機、關掉背景負載 |
Release 編譯:-O3 -lineinfo -Xptxas -v。
Nsight Systems:nsys profile -t cuda,nvtx --stats=true ./app
Nsight Compute(鎖定 1–2 支最花時間的 kernel):ncu --set full --kernels "regex"
小步優化:一次只改一件事(例如:把訪問改成連續、加 shared tile)。
重量測:用相同輸入與環境,取多次平均,寫下 改善百分比。
反覆:回到 2) 3) 再抓下一個瓶頸。
這就是專業團隊的常態工作流程。工具 + 方法論,沒有神奇捷徑。
先用 Nsight Systems 找「最大的慢點」→ 再用 Nsight Compute 拆解「單顆 kernel 的瓶頸」→ 按「記憶體、分歧、occupancy、算力、啟動」五大方向一條條對症下藥 → 量測、記錄、反覆。
當你會這一套,你已經具備把任何 CUDA 專案「從能跑,拉到會飛」的核心能力。